/*
 * Copyright (C) 2015 yixun All Rights Reserved.
 * 
 * ModelKeyServiceImpl.java
 */
package com.emm.yixun.basic.service.impl;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.emm.yixun.basic.exception.YIXUNUNCheckedException;
import com.emm.yixun.basic.mapper.ModelKeyMapper;
import com.emm.yixun.basic.model.ModelKey;
import com.emm.yixun.basic.model.dto.ModelKeyDto;
import com.emm.yixun.basic.service.ModelEnumService;
import com.emm.yixun.basic.service.ModelKeyService;
import com.emm.yixun.basic.system.util.DateUtil;
import com.emm.yixun.basic.system.util.SystemInfoUtil;


/**
 * [文件名称]<br>
 * ModelKeyServiceImpl.java<br>
 * <br>
 * [文件描述]<br>
 * 主键工厂 service interface impl<br>
 * <br>
 * [修改记录]<br>
 * 2015-05-26 12:54:22 创建 陶俊代码生成器<br>
 * 
 * @author 陶俊代码生成器
 * @version 1.00
 */
@Service("modelKeyService")
public class ModelKeyServiceImpl implements ModelKeyService {
	private static Log logger = LogFactory.getLog(ModelKeyServiceImpl.class);
	private final static long batchNum = 100000;
	private static Map<String,Long> currentMap = new HashMap<String,Long>();
	private static Map<String,Long> batchTimeMap = new HashMap<String,Long>();
	
	private static int  len = 6;//补位长度 初始步长6位数 设置不可小于6
	
	private static int errorTime = 0;
	
	private static int maxErrorTime = 3;
	
	@Autowired
	private ModelKeyMapper mapper;
	
	private static void setCurrent(String mKey,long current){
		currentMap.put(mKey,current);
	}
	
	private static void setCurrent(String dayStr,Enum<? extends ModelEnumService> modelEnum,long current){
		String mkey = modelEnum+"_"+dayStr;
		setCurrent(mkey,current);
	}
	
	private static long getCurrent(String mkey){
		if(!currentMap.containsKey(mkey)){
			currentMap.put(mkey,0l);
		}
		return currentMap.get(mkey).longValue();
	}
	
	private static long getCurrent(String dayStr,Enum<? extends ModelEnumService> modelEnum){
		String mkey = modelEnum+"_"+dayStr;
		if(!currentMap.containsKey(mkey)){
			currentMap.put(mkey,0l);
		}
		return currentMap.get(mkey).longValue();
	}
	
	private static long addCurrent(String dayStr,Enum<? extends ModelEnumService> modelEnum) {
		String mkey = modelEnum+"_"+dayStr;
		currentMap.put(mkey,getCurrent(mkey)+1);
		return getCurrent(mkey);
	}
	
	private static void setBatchTime(String dayStr,Enum<? extends ModelEnumService> modelEnum,long batchTime){
		String mkey = modelEnum+"_"+dayStr;
		batchTimeMap.put(mkey,batchTime);
	}
	
	private static int getBatchTime(String dayStr,Enum<? extends ModelEnumService> modelEnum){
		String mkey = modelEnum+"_"+dayStr;
		if(!batchTimeMap.containsKey(mkey)){
			batchTimeMap.put(mkey,0l);
		}
		return batchTimeMap.get(mkey).intValue();
	}
	
	public static String paddingStr(String p,int len,String padding){
		StringBuffer sb = new StringBuffer();
		if(StringUtils.isNotBlank(p)){
			for (int i=0;i<(len-p.getBytes().length);i++){
				sb.append(padding);
			}
		}
		return sb.toString()+p;
	}
	
	@Transactional
	@SuppressWarnings("finally")
	public String next(Enum<? extends ModelEnumService> modelEnum, String serverName){
		synchronized(modelEnum){
			String dayStr    = DateUtil.todayDateStr();
			String dayKeyStr = DateUtil.todayDateStr1();
			int res = 0;
			ModelKeyDto modelKey = new ModelKeyDto();
			modelKey.setDateStr(dayStr);
			modelKey.setModelName(modelEnum.name());
			
			//id池还有剩余
			if(getBatchTime(dayStr,modelEnum)>0&&getCurrent(dayStr,modelEnum)%batchNum>0){
				return ((ModelEnumService)modelEnum).modelPrex()+dayKeyStr+paddingStr(String.valueOf(addCurrent(dayStr,modelEnum)),len,"0"); 
			}
			
			ModelKey tModelKey = mapper.selectForUpdateByDto(modelKey);
			
			if(tModelKey!=null){
				modelKey.setUpdateTime(Calendar.getInstance().getTime());
				res = mapper.updateBatchNum(modelKey);
				tModelKey = mapper.selectById(tModelKey.getId());
				setBatchTime(dayStr,modelEnum,tModelKey.getBatchTime());
				setCurrent(dayStr,modelEnum,tModelKey.getIdCount());
				if(res==1){
					return ((ModelEnumService)modelEnum).modelPrex()+dayKeyStr+paddingStr(String.valueOf(getCurrent(dayStr,modelEnum)),len,"0");
				}else{
					throw new YIXUNUNCheckedException("重新批量请求ID异常");
				}
			}
			
			res = 0;
			try {
				setBatchTime(dayStr,modelEnum,1l);
				setCurrent(dayStr,modelEnum,1l);
				modelKey.setBatchTime(getBatchTime(dayStr,modelEnum));
				modelKey.setIdCount(getCurrent(dayStr,modelEnum));
				modelKey.setBatchNum(batchNum);
				modelKey.setCreateTime(Calendar.getInstance().getTime());
				res = mapper.add(modelKey);
			} catch (Exception e) {
				logger.error("新增批次请求失败,可能由于多服务器并发造成", e);
			}finally{
				if(res==0){
					if(errorTime<=maxErrorTime){
						try {
							Thread.sleep(1000);
                        } catch (InterruptedException e) {
                        	logger.warn("第"+errorTime+"次尝试生成主键时,主线程休眠异常:",e);
                        }
						setBatchTime(dayStr,modelEnum,0l);
						setCurrent(dayStr,modelEnum,0l);
						errorTime++;
						return next(modelEnum,serverName);
					}else{
						errorTime = 0;
						throw new YIXUNUNCheckedException("新增批次请求失败:"+maxErrorTime+"次，请日志检查基础配置.");
					}
				}else{
					return ((ModelEnumService)modelEnum).modelPrex()+dayKeyStr+paddingStr(String.valueOf(getCurrent(dayStr,modelEnum)),len,"0");
				}
			}
		}
	}

	public String next(Enum<? extends ModelEnumService> modelEnum) {
		return next(modelEnum,SystemInfoUtil.loadSystemInfo());
	}
	
}
